package org.lisen.oauth2example.resourceowner.controller;

import lombok.extern.slf4j.Slf4j;
import org.apache.oltu.oauth2.as.request.OAuthAuthzRequest;
import org.apache.oltu.oauth2.as.response.OAuthASResponse;
import org.apache.oltu.oauth2.common.OAuth;
import org.apache.oltu.oauth2.common.exception.OAuthProblemException;
import org.apache.oltu.oauth2.common.exception.OAuthSystemException;
import org.apache.oltu.oauth2.common.message.OAuthResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.*;
import java.util.concurrent.TimeUnit;

@Controller
@RequestMapping("/rowner")
@Slf4j
public class CodeController {

    @Autowired
    private StringRedisTemplate stringRedisTemplate;


    /**
     * 用户请求进行授权时，逻辑如下：
     * 1. 首先应判断客户的clientId是否合法，（暂时没有做严格验证，作为示例只对空进行了判断）
     * 2. 若合法，则对该请求生成唯一标识，并将请求信息进行缓存，并打开登录界面，在授权之前
     *    需要对资源拥有者的身份进行验证
     * 3. 若不合法，则提示错误信息
     * @param request 请求对象
     * @return
     */
    @GetMapping("/code")
    public String openAuthLoginPage(HttpServletRequest request) {
        String error = "";
        try {
            OAuthAuthzRequest oathReq = new OAuthAuthzRequest(request);
            String requestId = getRequestId();
            Map<String,Object> map = new HashMap<>();

            if(oathReq.getClientId() != null && !"".equals(oathReq.getClientId())) {
                map.put("clientId", oathReq.getClientId());
                map.put("redirectUri", oathReq.getRedirectURI());

                stringRedisTemplate.opsForHash().putAll("reqid:"+requestId, map);
                request.setAttribute("requestId", requestId);

                return "auth-login";
            } else {
                error = "客户需要先在完成信息的注册";
            }

        } catch (OAuthSystemException e) {
            e.printStackTrace();
            error = e.getMessage();
        } catch (OAuthProblemException e) {
            e.printStackTrace();
            error = e.getMessage();
        }

        request.setAttribute("errorInfo", error);
        return "error";
    }


    /**
     * 在授权之前，必须先验证资源拥有者的合法性，
     * 合法则显示授权页面，否则提示错误信息
     * @param request 请求对象
     * @param uname 用户名
     * @param passwd  密码
     * @param requestId  请求唯一标识
     * @return
     */
    @PostMapping("/login")
    public String openAuthPage(HttpServletRequest request, String uname, String passwd, String requestId) {

        if("lisen".equals(uname) && "123456".equals(passwd)) {
            request.setAttribute("requestId", requestId);
            return "auth";
        }

        request.setAttribute("errorInfo", "用户名或密码错误");
        return "error-info";
    }


    /**
     * 通过客户传过来的重定向url，将生成的code传给客户
     * @param request  请求对象
     * @param requestId  请求的唯一标识
     * @return
     * @throws OAuthSystemException
     */
    @GetMapping("/sendcode")
    public String sendCode(HttpServletRequest request, String requestId) throws OAuthSystemException {

        log.info("resource owner send code ");

        //设置授权码
        String code = getCode();

        //将code放入缓存，并设置过期时间为5分钟，requestId为请求唯一标识，可以标记code
        //属于哪一次请求生成
        stringRedisTemplate.opsForValue().set(code, requestId, 60*5, TimeUnit.SECONDS);

        //从缓存中获取客户传过来的重定向url
        String redirectUri = stringRedisTemplate.opsForHash().get("reqid:" + requestId, "redirectUri")+"";

        //获取构建响应的对象
        OAuthASResponse.OAuthAuthorizationResponseBuilder builder = OAuthASResponse.authorizationResponse(request, HttpServletResponse.SC_FOUND);
        builder.setCode(code);

        OAuthResponse oauthResp = builder.location(redirectUri).buildQueryMessage();

        log.info("resource owner send code ：" + code);
        String uri = oauthResp.getLocationUri();

        return"redirect:" + uri;
    }


    //生成一个随机的8位授权码
    public String getCode() {
        Random r = new Random();
        String code = "";
        for (int i = 0; i < 8; ++i) {
            int temp = r.nextInt(52);
            char x = (char) (temp < 26 ? temp + 97 : (temp % 26) + 65);
            code += x;
        }
        return code;
    }


    //获取请求ID，用户唯一标识一个请求
    private String getRequestId() {
        return UUID.randomUUID().toString().replaceAll("-", "");
    }

}
